﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using NicoView.Model.Service;
using WindowsCommonStorage;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using System.IO;
using System.Windows.Input;
using NicoView.Model.Service.Events;
using NicoView.Model.Service.Files;
using NicoView.Model.Service.Errors;
using NicoView.Model.Speech;
using NicoView.Model.Service.Property;
using LibNiconico.NiconicoApi.Mylist;
using NicoView.Model.Service.Results;
using NicoView.Model.Service.Lives;
using System.Text.RegularExpressions;
using LibNiconico.NiconicoApi.Videos;
using System.Threading;
using NicoView.Model.Service.Comments;
using LibNiconico.NiconicoApi.Videos.ThumbInfo;
using LibNiconico.NiconicoApi.Alert;
using LibNiconico.NiconicoApi;
using NicoView.Model.Service.Broadcast;
using LibNiconico.NiconicoApi.Lives.Broadcast;
using System.ComponentModel;
using NicoView.Model.Share.Service;
using NicoView.Model.Share.Speech;
using LibNiconico.NiconicoApi.Utils;
using LibNiconico.NiconicoApi.PlayerStatus;
using NicoView.Model.MediaEncoder;

namespace NicoView.Model.Service
{

    /// <summary>
    /// ニコニコサービスインスタンス
    /// </summary>
    public class NicoServiceApplicationInstance : NicoViewObservableObject, IDisposable
    {
        /// <summary>
        /// サービスがセットされていない場合に呼び出されるハンドラ
        /// </summary>
        /// <param name="args"></param>
        public delegate void ServieceNotSet(NicoServiceRequieSetEventArgs args);



        static NicoServiceApplicationInstance()
        {
            NicoApiHelperSettings.SetUserAgent("NicoView");
        }



        public NotificationNicoSelfUser SelfUser
        {
            get
            {
                return this.selfUser;
            }

            set
            {
                if (this.selfUser != null)
                {
                    this.selfUser.PropertyChanged -= selfUser_PropertyChanged;
                }
                
                this.Set(() => this.SelfUser, ref this.selfUser, value);

                this.selfUser.PropertyChanged += selfUser_PropertyChanged;
            }
        }

        void selfUser_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.RaisePropertyChangedAll();
        }




        /// <summary>
        /// このプロバイダに割り当てれられているニコニコアラートAPIヘルパー
        /// </summary>
        private NicoAlertApiHelper alertApi { get; set; }

        private NotificationNicoSelfUser selfUser;

        private INiconicoAlertClient alertClient;

        internal bool Connecting { get; private set; }

        public INiconicoAlertClient AlertClient
        {
            get
            {
                return this.alertClient;
            }

            set
            {
                if (this.alertClient != null)
                {
                    this.alertClient.Dispose();
                }
                this.alertClient = value;
                this.alertClient.Received += onAlertNotifyReceived;
            }
        }

        private async void onAlertNotifyReceived(NicoAlertNotificationMessageReceiveArgs args)
        {
            if (this.CurrentService != null && this.Property.NextFrameAutoConnection)
            {
                var matchNotifys = from notify in args.Messages
                                   where !notify.IsOfficial && notify.CommunityOrChannnelId == this.CurrentService.ServiceInfo.CommunityId && notify.Id != this.CurrentService.ServiceInfo.Id && alertLiveIdRegex.Match(notify.Id).Success
                                   select notify.Id;

                if (matchNotifys.Count() > 0)
                {
                    var liveId = matchNotifys.First();
                    await this.ConnectServiceAsync(liveId);

                    if (this.Property.NextFrameAutoConnectionWithBrowser)
                    {
                        this.BaseApplication.ExecuteLiveUrl(liveId);
                    }
                }

            }
        }


        /// <summary>
        /// 現在の割り当てられているサービス
        /// </summary>
        public INicoService CurrentService { get; private set; }

        internal void SetLiveService(NicoLiveService liveService)
        {

            if (CurrentService != null)
            {
                SpeechApplication.SpeechCancel();

                var oldService = CurrentService;
                oldService.Dispose();
            }
            CurrentService = liveService;
            CurrentService.CommentClient.Received += onReceiveComment;

            SpeechApplication.SpeechStart();

            this.RaisePropertyChangedAll();
        }

        /// <summary>
        /// このプロバイダに割り当てられているニコニコAPIヘルパー
        /// </summary>
        private NicoApiHelper Api { get; set; }


        /// <summary>
        /// このサービスインスタンスがログインしているか確認
        /// </summary>
        public bool IsSetAuth
        {
            get
            {
                return this.Api.IsSetAuth;
            }

        }

        public NotificationNicoAuth Auth { get; private set; }


        /// <summary>
        /// コメント受信時に呼び出されるメソッド
        /// </summary>
        /// <param name="args"></param>
        private async void onReceiveComment(NicoCommentReceiveEventArgs args)
        {
            foreach (var comment in args.Comments)
            {
                comment.GetApiInfo += () =>
                {
                    UserApiInfoSetter.SetUserApiInfoRequest(comment.User);
                };

                if (checkSpeechComment(comment)) await this.SpeechApplication.SpeechAsync(new SynthesizeArgs(comment.GetDisplayBody(), GetDisplayName(comment), SpeechEnable));
            }


        }

        /// <summary>
        /// コメントがスピーチ対象になるかチェック
        /// </summary>
        /// <param name="comment"></param>
        /// <returns></returns>
        private bool checkSpeechComment(NotifyNicoComment comment)
        {
            return SpeechEnable &&
                    comment.IsNew &&
                    (comment.BodyType == CommentBodyType.Normal || comment.BodyType == CommentBodyType.ShowCommand) &&
                    (!comment.CommentScoreRank.IsNotShowNgRank(this.BaseApplication.Property.CommentNgShareLevel)) &&
                    (!((!this.Property.VisibleAnonymous) && comment.IsAnonymous));
        }


        /// <summary>
        /// コメント情報をもとに表示名を取得
        /// </summary>
        /// <param name="comment"></param>
        /// <returns></returns>
        public string GetDisplayName(NotifyNicoComment comment)
        {
            if (comment.HasBeenSetCustomName || this.Property.VisibleCustomNameOnly)
            {
                return comment.GetDisplayName();
            }
            else
            {
                return "";
            }

        }


        public NicoViewProperty Property
        {
            get
            {
                return this.BaseApplication.Property;
            }
        }




        /// <summary>
        /// このサービスインスタンスに割り当てられているコメント送信変換オブジェクトを取得
        /// </summary>
        public SubmitCommentConversions SubmitCommentConversions
        {
            get
            {
                return this.BaseApplication.Property.SubmitCommentConversions;
            }
        }



        /// <summary>
        /// ID文字列をもとに適切なサービスに接続
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<INiconicoConnectionResult> ConnectServiceAsync(string id)
        {
            lock (this)
            {
                if (this.Connecting)
                {
                    return new NiconicoConnectionResult(NiconicoConnectionResultCode.Connecting, false, "接続中です");
                }
            }

            try
            {
                this.Connecting = true;
                INiconicoConnectionResult result = null;
                do
                {

                    var liveMatch = liveIdRegex.Match(id);
                    if (liveMatch.Success)
                    {
                        result = await ConnectLiveService(liveMatch.Value);

                    }
                    else
                    {
                        var liveUrlMatch = liveUrlRegex.Match(id);
                        if (liveUrlMatch.Success)
                        {
                            result = await ConnectLiveService(liveUrlMatch.Groups[@".+"].Value);

                        }
                    }



                    if (result != null && result.NotLogin)
                    {

                        if (await this.LoginAsync())
                        {
                            await setSelfUserInfoAsync();
                            continue;
                        }
                        else
                        {
                            return new NiconicoConnectionResult(NiconicoConnectionResultCode.NotLogin, false, "ログインできませんでした");
                        }
                    }
                    else if (result == null)
                    {
                        return new NiconicoConnectionResult(NiconicoConnectionResultCode.Fail, false, "接続に失敗しました");
                    }
                    {
                        return result;
                    }

                } while (true);

            }
            finally
            {
                this.Connecting = false;
            }

        }

        /// <summary>
        /// 配信中のコントローラ
        /// </summary>
        public NicoViewBroadcastController BroadcastingController
        {
            get
            {
                return this.broadcastingController;
            }

            set
            {
                this.Set(() => this.BroadcastingController, ref this.broadcastingController, value);
            }

        }

        private NicoViewBroadcastController broadcastingController;


        /// <summary>
        /// 配信エンコードの開始
        /// </summary>
        public void StartBroadcatEncode()
        {
            if (this.BroadcastingController != null)
            {
                this.BroadcastingController.StartEncode();
            }
        }

        /// <summary>
        /// 配信エンコードの停止
        /// </summary>
        public void StopBroadcastEncode()
        {
            if (this.BroadcastingController != null)
            {
                this.BroadcastingController.StopEncode();
            }
        }


        /// <summary>
        /// 配信を非同期に開始
        /// </summary>
        /// <param name="controller"></param>
        /// <returns></returns>
        internal async Task<NicoViewStartBroadcastResult> StartBroadcastAsync(NicoViewBroadcastController controller)
        {

            if (this.CurrentService != null)
            {
                this.CurrentService.Dispose();
                this.CurrentService = null;
            }


            if (this.SelfUser == null) return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.NotLogin, "ログインしていません");

            if (controller.CurrentCommunityInfo == null) return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.InvalidCommunityId, "コミュニティIDが設定されていません");

            var createBroadcastQuery = controller.CreateAsBroadcastCreateQueryInfo();

            controller.EnableRequest = true;

            var createBroadcastResponse = await this.Api.BroadcastApi.CreateLiveBroadcastAsync(createBroadcastQuery);

            NicoViewStartBroadcastResult result = null;

            if (controller.EnableRequest)
            {
                if (createBroadcastResponse.Succeed)
                {
                    result = await this.startBroadcastAsync(createBroadcastResponse.LiveInfo);


                }
                else if (createBroadcastResponse.IsQueueing)
                {

                    result = await this.waitForStartBroadcastAsync(controller, createBroadcastResponse.LiveInfo);

                }

                else
                {
                    return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.Fail, createBroadcastResponse.Message);
                }
            }
            else
            {
                return NicoViewStartBroadcastResult.CreateCancel();
            }



            if (result != null && result.Succeed)
            {
                controller.BroadcastingLiveId = createBroadcastResponse.LiveInfo.LiveId;

                controller.IsBroadcasting = true;

                

                await this.ConnectLiveService(controller.BroadcastingLiveId);

                controller.Encoder = MediaEncoders.Current.CurrentProvider.Create();

                if (this.Property.UsingBroadcasatEncoder)
                {
                    controller.StartEncode();
                }
            }


            return result;
        }


        private async Task<NicoViewStartBroadcastResult> waitForStartBroadcastAsync(NicoViewBroadcastController controller, NicoLiveBroadcastableLiveInfo liveInfo)
        {
            NicoLiveBroadcastWaitInfoResponse waitInfoResponse = null;
            do
            {

                waitInfoResponse = await this.Api.BroadcastApi.GetWaitInfoAsync(liveInfo);

                if (!waitInfoResponse.Succeed) return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.Fail, "放送開始待機中にエラーが発生しました");

                if (!controller.EnableRequest)
                {
                    return NicoViewStartBroadcastResult.CreateCancel();
                }

                if (waitInfoResponse.StreamStatus == NicoLiveBroadcastWaitInfoStreamStatus.StartPossible) return await this.startBroadcastAsync(liveInfo);
                controller.OnQueued(new NicoViewBroadcastQueueingEventArgs(waitInfoResponse));

            } while (waitInfoResponse.StreamStatus == NicoLiveBroadcastWaitInfoStreamStatus.Waiting);

            return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.Fail, "開始待機中に不明なコードが返されました");

        }

        private async Task<NicoViewStartBroadcastResult> startBroadcastAsync(NicoLiveBroadcastableLiveInfo liveInfo)
        {
            var startResponse = await this.Api.BroadcastApi.StartBroadcastAsync(liveInfo);

            if (startResponse.Succeed)
            {
                return new NicoViewStartBroadcastResult();
            }
            else
            {
                return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.Fail, "原因不明のエラーです");
            }
        }


        /// <summary>
        /// 非同期にプレイヤーステータスを取得
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        internal async Task<NicoGetPlayerStatusResponse> GetPlayerStatusAsync(string id)
        {
            return await this.Api.LiveApi.GetPlayerStatusAsync(id).ConfigureAwait(false);
        }


        /// <summary>
        /// 非同期に次枠自動取得
        /// </summary>
        /// <returns></returns>
        internal async Task<NicoViewStartBroadcastResult> AutoStartNextBroadcastAsync()
        {

            if (this.BroadcastingController != null && this.BroadcastingController.IsBroadcasting)
            {

                await this.BroadcastingController.StopBroadcastAsync();

                return await this.BroadcastingController.StartBroadcastAsync();


            }

            return new NicoViewStartBroadcastResult(NicoViewStartBroadcastResultCode.Fail, "放送中ではありません");

        }


        /// <summary>
        /// 非同期に放送中の配信を停止
        /// </summary>
        /// <returns></returns>
        internal async Task<NicoViewStopBroadcastResult> StopBroadcastAsync(NicoViewBroadcastController controller)
        {
            if (controller.IsBroadcasting)
            {
                NicoViewStopBroadcastResult result;
                
                if (this.SelfUser == null) return new NicoViewStopBroadcastResult(NicoViewStopBroadcastResultCode.NotLogin, "ログインしていません");

                var response = await this.Api.BroadcastApi.StopBroadcastAsync(controller.BroadcastingLiveId);

                if (response.Succeed)
                {
                    result =  new NicoViewStopBroadcastResult(NicoViewStopBroadcastResultCode.Succeed, "放送を停止しました");
                }
                else
                {
                    result =  new NicoViewStopBroadcastResult(NicoViewStopBroadcastResultCode.Fail, "放送停止に失敗しました");
                }

                
                
                controller.IsBroadcasting = false;
                await this.DisconnectServiceAsync();


                return result;
            }

            return new NicoViewStopBroadcastResult(NicoViewStopBroadcastResultCode.Fail, "放送していません");
        }


        /// <summary>
        /// ニコニコ生放送に接続
        /// </summary>
        /// <param name="liveId"></param>
        /// <returns></returns>
        public async Task<INiconicoConnectionResult> ConnectLiveService(string liveId)
        {





            var liveResult = await this.createNicoLiveServiceAsync(liveId);

            if (liveResult.Succeed)
            {

                SetLiveService(liveResult.Value);
                _onLiveConntected(new NicoLiveServiceConnectedEventArgs(this.BaseApplication, liveResult.Value));
                await liveResult.Value.CommentServerConnectAsync();
                liveResult.Value.Timer.Start();

                if (this.BaseApplication.Property.NextFrameAutoConnection)
                {
                    if (this.AlertClient == null)
                    {
                        this.AlertClient = await this.CreateGeneralNiconicoAlertAsync();
                    }

                    if (!this.AlertClient.Connected)
                    {
                        await this.AlertClient.ConnectAsync();
                    }
                }

            }
            return liveResult;



        }

        /// <summary>
        /// 生放送サービスを非同期に生成
        /// </summary>
        /// <param name="liveId"></param>
        /// <returns></returns>
        public async Task<NiconicoLiveConnectionResult> createNicoLiveServiceAsync(string liveId)
        {
            if (!await AuthenticateAsync()) return new NiconicoLiveConnectionResult(false, null, false, "ユーザ登録を中止しました");
            var liveConnectionResponse = await this.Api.LiveApi.ConnectLiveAsync(liveId);




            if (liveConnectionResponse.PlayerStatusResponse.Status.Code != NicoApiResponseStatusCode.OK)
            {
                string errResult = "";
                errResult = liveConnectionResponse.PlayerStatusResponse.Error.Description;
                return new NiconicoLiveConnectionResult(liveConnectionResponse.PlayerStatusResponse, null, false, errResult);

            }



            var liveService = new NicoLiveService(liveConnectionResponse.PlayerStatusResponse.PlayerStatus, liveConnectionResponse.CommentClient, this.BaseApplication);
            liveService.UserRequest += (e) =>
            {
                e.User = this.BaseApplication.Property.NicoUsers.CreateIfNotExsits(e.Id);
            };
            return new NiconicoLiveConnectionResult(false, liveService, true, "");
        }

        internal async Task<INiconicoAlertClient> CreateGeneralNiconicoAlertAsync()
        {
            return (await this.alertApi.GetAlertInfoAsync()).AlertClient;
        }

        public async Task DisconnectServiceAsync()
        {
            await Task.Run(async () =>
            {
                if (this.CurrentService.ServiceType == NicoServiceType.Live && this.CurrentService.ServiceInfo.IsOwner)
                {
                    var liveService = (NicoLiveService)this.CurrentService;
                    await liveService.MainCommentClient.SendDisconnectComment().ConfigureAwait(false);
                }

                this.CurrentService.Dispose();
            }).ConfigureAwait(false);

        }

        /// <summary>
        /// 配信開始に必要な情報を取得
        /// </summary>
        /// <returns></returns>
        internal async Task<IResult<NicoLiveBroadcastableInfoGetResponse>> GetBroadcastableInfoAsync()
        {
            var response = await this.Api.BroadcastApi.GetBroadcastableInfoAsync();

            return new Result<NicoLiveBroadcastableInfoGetResponse>(response, response.Succeed, "");
        }


        /// <summary>
        /// ニコニコ動画管理コンソール呼び出しをリクエスト
        /// </summary>
        /// <param name="videoId"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public async Task<Result<bool>> VideoConsolRequestAsync(string videoId, Action<NicoVideoConsoleEventArgs> action)
        {
            try
            {

                var videoInfoRes = await this.Api.VideoApi.GetThumbInfoAsync(videoId);

                if (!videoInfoRes.Succeed)
                {

                    return new Result<bool>(true, videoInfoRes.Succeed, "動画情報取得エラー" + videoInfoRes.Error.Description);
                }


                bool execute = false;
                var requestResponse = await this.Api.MylistApi.AddMylistRequestAsync(videoId);
                var eventArgs = new NicoVideoConsoleEventArgs(new NicoVideoInfoConsoleEventArgs(videoInfoRes.Thumb, requestResponse.MylistItems));


                eventArgs.AddFunc = async () =>
                {
                    execute = true;
                    var executeResponse = await this.Api.MylistApi.AddMylistExecuteAsync(eventArgs.AddTarget, requestResponse);
                    return new Result<bool>(execute, executeResponse.Result.Succeed, executeResponse.Result.Description);
                };

                action(eventArgs);

                return new Result<bool>(false);
            }
            catch
            {
                return new Result<bool>(true, false, "動画情報取得できませんでした");
            }
        }



        /// <summary>
        /// 生放送接続時に呼び出されるイベントハンドラ
        /// </summary>
        public event NicoLiveServiceConnectedHandler LiveConnected;


        /// <summary>
        /// 生放送接続時に実行されるメソッド
        /// </summary>
        /// <param name="args"></param>
        private void _onLiveConntected(NicoLiveServiceConnectedEventArgs args)
        {
            if (LiveConnected != null) LiveConnected(args);
        }
















        private static readonly Regex alertLiveIdRegex = new Regex(NicoFormat.LIVEID_FORMAT);

        private static readonly Regex videoIdRegex = new Regex(NicoFormat.VIDEOID_FORMAT);

        private static readonly Regex liveIdRegex = new Regex(NicoFormat.LIVEID_FORMAT + "|" + NicoFormat.CHANNEL_FORMAT + "|" + NicoFormat.COMMUNITY_FORMAT);

        private static readonly Regex videoUrlRegex = new Regex(@"http://(www.)?nicovideo.jp/watch/(.+)");

        private static readonly Regex liveUrlRegex = new Regex(@"http://((live.nicovideo.jp)|(watch.live.nicovideo.jp))/watch/(.+)");









        internal NicoViewApplication BaseApplication;

        internal NicoServiceApplicationInstance(NicoViewApplication baseApplication)
        {

            this.BaseApplication = baseApplication;
            this.UserApiInfoSetter = new NicoUserApiInfoSetRequestManager(this);
            this.CurrentService = null;
            this.alertApi = new NicoAlertApiHelper();
            this.Api = new NicoApiHelper();
            this.Auth = new NotificationNicoAuth();
            this.loginMutex = new Mutex();
            this.SpeechApplication = new NicoSpeechServiceApplication(NicoViewSpeacherApplication.Current);

        }




        public async Task CurrentAuthSetRequest()
        {



            var planeAuth = new NicoPlaneUserAuth();

            var eventArgs = new NicoServiceRequieSetEventArgs("アカウント情報変更", planeAuth);

            NicoUserAuth userAuth = null;
            eventArgs.OnSet += (args) =>
            {




                userAuth = args.Auth;



            };
            this.BaseApplication.OnSetRequest(eventArgs);

            if (userAuth != null)
            {
                var result = await this.LoginAsync(userAuth);

                if (result)
                {
                    await setSelfUserInfoAsync();
                }

            }



        }



        public bool SpeechEnable
        {
            get
            {
                return this.Property.SpeechEnable;
            }
            set
            {
                if (value)
                {
                    this.SpeechApplication.SpeechStart();

                }
                else
                {
                    this.SpeechApplication.SpeechCancel();

                    RaisePropertyChanged("SpeechEnable");

                }

                this.Property.SpeechEnable = value;
            }
        }

        /// <summary>
        /// ユーザ情報にニコニコのAPIから取得できる情報を割り当てる
        /// </summary>
        /// <param name="user"></param>
        /// <returns></returns>
        public async Task SetApiUserInfo(NotificationNicoUser user)
        {
            var getThumbRslt = await this.Api.UserApi.GetThumbUserAsync(user.Id);

            NicoViewApplication.Current.SynchronizationContext.Send((s) =>
            {
                user.NickName = getThumbRslt.UserName;
                user.UserIconPath = getThumbRslt.UserImagePath;
            }, null);

        }

        /// <summary>
        /// 現在設定されているユーザ認証情報の認証を非同期に行う
        /// </summary>
        /// <returns></returns>
        public async Task<bool> AuthenticateAsync()
        {
            if (this.loginMutex.WaitOne(0))
            {

                try
                {
                    var result = this.Api.IsSetAuth;
                    if (!result)
                    {


                        if (this.Auth == null || !this.Auth.Auth.IsEnableAuth())
                        {

                            result = await LoginAsync();



                        }
                        else
                        {
                            this.Api.SetUserSession(this.Auth.Auth.GetUserSession());
                            result = true;
                        }

                        

                    }
                   

                    if (result)
                    {
                        await setSelfUserInfoAsync();
                    }

                    return result;

                }
                finally
                {
                    loginMutex.ReleaseMutex();
                }
            }
            else
            {
                return false;
            }

        }

        #region ログイン

        /// <summary>
        /// 非同期にログイン
        /// </summary>
        /// <returns></returns>
        public async Task<bool> LoginAsync()
        {
            NicoUserAuth auth;

            if (this.Auth == null || string.IsNullOrEmpty(this.Auth.Mail))
            {

                auth = this.BaseApplication.OnServieceNotSet() ?? new NicoPlaneUserAuth();



            }
            else
            {
                auth = new NicoPlaneUserAuth();
            }

            return await LoginAsync(auth);
        }

        internal async Task<bool> LoginAsync(NicoUserAuth auth)
        {


            bool result = await loginAsync(auth.Mail, auth.PassWord);

            if (!result)
            {


                var eventArgs = new NicoServiceRequieSetEventArgs("認証情報の保存期間がきれた。または登録されているユーザでは認証できません。\r\nユーザ情報を登録しなおしてください", auth);
                eventArgs.OnSet += args =>
                {
                    auth = args.Auth;

                };
                this.BaseApplication.OnFailAuth(eventArgs);
                result = await loginAsync(auth.Mail, auth.PassWord);



            }

            return result;
        }

        private async Task<bool> loginAsync(string mail, string password)
        {
            Api.ClearAuth();
            var result = await Api.LoginAsync(mail, password).ConfigureAwait(false);

            if (result.Succeed)
            {

                this.Auth.UserSession = Api.GetUserSession();
                return true;
            }

            return false;
        }

        #endregion

        private async Task setSelfUserInfoAsync()
        {
            try
            {
                if ((await SetSelfUserInfoAsync().ConfigureAwait(false)).Succeed)
                {
                    this.UserApiInfoSetter.SetUserApiInfoRequest(this.SelfUser.AsNotifyNicoUser());
                }


            }
            catch
            {

            }

        }


        public async Task<Result> SetSelfUserInfoAsync()
        {
            var resposne = await this.Api.LiveApi.ConnectLiveAsync("lv19800507");

            if (resposne.Succeed)
            {
                this.SelfUser = new NotificationNicoSelfUser(this.BaseApplication.Property.NicoUsers.CreateIfNotExsits(resposne.PlayerStatusResponse.PlayerStatus.User.UserId), resposne.PlayerStatusResponse.PlayerStatus.User.IsPremium);
                return new Result();
            }
            else
            {
                return new Result(false);
            }
        }

        private Mutex loginMutex;

        public NicoSpeechServiceApplication SpeechApplication { get; private set; }

        public NicoUserApiInfoSetRequestManager UserApiInfoSetter { get; private set; }

        public void Dispose()
        {

            this.SpeechApplication.Dispose();

        }




    }
}
